import { WebGLCanvas } from "@nirvana/canvas";
import {
  AmbientLight,
  BallGeometry,
  Camera,
  Data,
  DataElement,
  DirectionalLight,
  Geometry,
  HemisphereLight,
  Mesh,
  PlaneGeometry,
  PointLight,
  SceneNode,
  ShaderMaterial
} from "@nirvana/core";
import { Color, Vector3 } from "@nirvana/math";
import { Shader } from "@nirvana/shaders";

async function main() {
  let canvas = document.getElementById("engine-nirvana");
  const webCanvas = new WebGLCanvas(canvas, {
    rate: 1
  });
  const engine = webCanvas.engine;

  const scene = engine.sceneManager.createScene("root");
  const camera = new Camera("", engine);
  scene.addCamera(camera);
  camera.transform.setPosition(0, 0, 20);
  const rootEntity = new SceneNode("root-entity");
  scene.addEntity(rootEntity);

  const ambLight = new AmbientLight("alight");
  ambLight.color.set(0.1, 0.1, 0.1, 1);
  scene.addLight(ambLight);

  const vs = `
  attribute vec4 POSITION;
  attribute vec3 NORMAL;
  attribute vec2 TEXCOORD_0;

  uniform vec4 COLOR;

  // uniform mat4 u_localMat;
  uniform mat4 u_modelMat;
  uniform mat4 u_viewMat;
  uniform mat4 u_projMat;
  uniform mat4 u_MVMat;
  // uniform mat4 u_MVPMat;
  uniform mat4 u_normalMat;
  uniform vec3 u_cameraPos;

  varying vec3 v_position;
  varying vec3 v_normal;
  varying vec4 v_color;
  varying vec2 v_uv0;

  varying vec3 v_surfaceToLight;
  varying vec3 v_surfaceToView;

  uniform vec3 u_DIRECTIONALLIGHT_COLOR;
  uniform vec3 u_DIRECTIONALLIGHT_POSITION;
  uniform vec3 u_DIRECTIONALLIGHT_DIRECTION;

  void main() {
    gl_Position = u_projMat * u_viewMat * u_modelMat * POSITION;

    v_position = (u_modelMat * POSITION).xyz;
    v_normal = mat3(u_normalMat) * NORMAL;
    v_color = COLOR;
    v_uv0 = TEXCOORD_0;

    // compute the world position of the surfoace
    vec3 surfaceWorldPosition = v_position.xyz;

    // compute the vector of the surface to the light
    // and pass it to the fragment shader
    v_surfaceToLight = (u_DIRECTIONALLIGHT_POSITION - surfaceWorldPosition);

    // compute the vector of the surface to the view/camera
    // and pass it to the fragment shader u_cameraPos
    v_surfaceToView = normalize(u_cameraPos - surfaceWorldPosition);
  }
  `;
  const fs = `
  uniform mat4 u_localMat;
  uniform mat4 u_modelMat;
  uniform mat4 u_viewMat;
  uniform mat4 u_projMat;
  uniform mat4 u_MVMat;
  uniform mat4 u_MVPMat;
  uniform mat4 u_invMat;
  uniform mat4 u_normalMat;
  uniform vec3 u_cameraPos;

  uniform vec3 u_AMBIENTLIGHT_COLOR;

  uniform vec3 u_DIRECTIONALLIGHT_COLOR;
  uniform vec3 u_DIRECTIONALLIGHT_POSITION;
  uniform vec3 u_DIRECTIONALLIGHT_DIRECTION;
  uniform float u_DIRECTIONALLIGHT_INTENSITY;

  varying vec3 v_position;
  varying vec3 v_normal;
  varying vec4 v_color;

  varying vec3 v_surfaceToLight;
  varying vec3 v_surfaceToView;

  void main() {

    vec3 ambient = u_AMBIENTLIGHT_COLOR * v_color.rgb;// 计算环境光反射颜色

    float specularIntensity = 0.8; // 镜面强度， 值越大，反射光的强度就越大 step(cos,0.0)
    vec3 specularColor = vec3(1.0,1.0,1.0); // 高光颜色，默认为白色
    float shininess = 32.0; // 亮光集中度，值越大，点越小30 -100
    float k = 2.0; // 值越大，diffuse范围越广

    // 对发现进行归一化处理
    vec3 normal = normalize(v_normal);
    // 计算光线方向并归一化
    vec3 lightDirection = normalize(u_DIRECTIONALLIGHT_DIRECTION);
    vec3 surfaceToViewDirection = normalize(v_surfaceToView);

    // 计算光线方向和法向量的点积
    float cos = max(dot(lightDirection, normal), 0.0);// 计算入射角余弦值
    vec3 diffuse = u_DIRECTIONALLIGHT_COLOR * vec3(v_color) * cos * k;// 计算平行光漫反射颜色

    // //高光反射模型C specular=(Clight*Mspecular）*pow(max(0,dot(V,R)),Mgloss)
    // // 宾氏模型高光, 平行光不计等位置，所以方向与顶点位置有关
    // vec3 halfVector = normalize(lightDirection + surfaceToViewDirection);
    // float specularWeighting = pow(clamp(dot(normal, halfVector), 0.0, 1.0), shininess);
    // vec3 specular = specularColor * specularWeighting * specularIntensity;

    // // 冯氏模型高光
    // vec3 reflectionDirection = reflect(-lightDirection, normal);
    // float specularWeighting = pow(max(dot(reflectionDirection, surfaceToViewDirection), 0.0), shininess);
    // vec3 specular = specularColor * specularWeighting * specularIntensity;

    // gl_FragColor = vec4(specular + diffuse + ambient, v_color.a);// 叠加作为最终的颜色
    gl_FragColor = vec4(diffuse + ambient, v_color.a);// 叠加作为最终的颜色
    gl_FragColor.rgb *= u_DIRECTIONALLIGHT_INTENSITY;
  }
`;

  const shader = Shader.create("light-demo", vs, fs);
  const material = new ShaderMaterial("", shader);
  material.shaderData.setColor("COLOR", new Color(0.25, 0.25, 0.75, 1.0));

  const gem = new BallGeometry(2, 64, 64);
  const ball = new Mesh(gem, material);
  ball.transform.setPositionZ(10);
  // rootEntity.addChildNode(ball);
  scene.addEntity(ball);

  const plane = new PlaneGeometry();
  const planeMesh = new Mesh(plane, material);
  // scene.addEntity(planeMesh);
  // rootEntity.addChildNode(planeMesh);

  const dLight = new DirectionalLight("plight");
  dLight.direction.set(0, 10, -10);
  dLight.color.set(1.0, 0.0, 0.0, 1.0);
  dLight.intensity = 2.0;
  scene.addLight(dLight);

  let i = 0.01;
  engine.update = () => {
    if (rootEntity.transform.position.x <= -3) {
      rootEntity.transform.setPositionX(-2.9);
      i = 0.01;
    } else if (rootEntity.transform.position.x >= 3) {
      rootEntity.transform.setPositionX(2.9);
      i = -0.01;
    }

    rootEntity.transform.translate(i, 0, 0);

    ball.transform.rotate(0, -0.01, 0);
  };
}

main();
